#!/usr/bin/env python3
"""
Redis缓存策略实现
支持推荐结果缓存、热点内容缓存、用户行为缓存
"""

import json
import hashlib
from typing import List, Dict, Any, Optional
from datetime import datetime, timedelta
import asyncio

from config.redis import RedisUtils, RedisKeys

class RecommendationCache:
    """推荐缓存管理器"""
    
    def __init__(self):
        self.redis_utils = RedisUtils
        self.cache_prefix = "recommend"
        self.default_expire = 600  # 10分钟
        self.hot_content_expire = 3600  # 1小时
    
    def _generate_cache_key(self, key_type: str, **kwargs) -> str:
        """生成缓存键"""
        # 对参数进行排序，确保键的一致性
        sorted_params = sorted(kwargs.items())
        param_str = "&".join([f"{k}={v}" for k, v in sorted_params])
        
        # 生成MD5哈希，避免键过长
        hash_obj = hashlib.md5(param_str.encode())
        hash_str = hash_obj.hexdigest()[:8]
        
        return f"{self.cache_prefix}:{key_type}:{hash_str}"
    
    async def cache_user_recommendations(
        self,
        user_id: int,
        page: int,
        recommendations: List[Dict[str, Any]],
        expire: int = None
    ) -> bool:
        """缓存用户推荐结果"""
        try:
            cache_key = self._generate_cache_key(
                "user_rec", 
                user_id=user_id, 
                page=page
            )
            
            cache_data = {
                "user_id": user_id,
                "page": page,
                "recommendations": recommendations,
                "cached_at": datetime.utcnow().isoformat(),
                "count": len(recommendations)
            }
            
            expire_time = expire or self.default_expire
            success = self.redis_utils.set(
                cache_key, 
                json.dumps(cache_data, ensure_ascii=False),
                expire_time
            )
            
            if success:
                print(f"用户 {user_id} 第 {page} 页推荐结果缓存成功")
            
            return success
            
        except Exception as e:
            print(f"缓存用户推荐结果失败: {e}")
            return False
    
    async def get_user_recommendations(
        self,
        user_id: int,
        page: int
    ) -> Optional[List[Dict[str, Any]]]:
        """获取用户推荐结果缓存"""
        try:
            cache_key = self._generate_cache_key(
                "user_rec",
                user_id=user_id,
                page=page
            )
            
            cached_data = self.redis_utils.get(cache_key)
            if not cached_data:
                return None
            
            cache_info = json.loads(cached_data)
            recommendations = cache_info.get("recommendations", [])
            
            print(f"从缓存获取用户 {user_id} 第 {page} 页推荐结果，共 {len(recommendations)} 条")
            return recommendations
            
        except Exception as e:
            print(f"获取用户推荐缓存失败: {e}")
            return None
    
    async def cache_hot_content_by_tag(
        self,
        tag_id: int,
        hot_contents: List[Dict[str, Any]],
        expire: int = None
    ) -> bool:
        """缓存标签热门内容"""
        try:
            cache_key = self._generate_cache_key(
                "hot_content",
                tag_id=tag_id
            )
            
            cache_data = {
                "tag_id": tag_id,
                "hot_contents": hot_contents,
                "cached_at": datetime.utcnow().isoformat(),
                "count": len(hot_contents)
            }
            
            expire_time = expire or self.hot_content_expire
            success = self.redis_utils.set(
                cache_key,
                json.dumps(cache_data, ensure_ascii=False),
                expire_time
            )
            
            if success:
                print(f"标签 {tag_id} 热门内容缓存成功，共 {len(hot_contents)} 条")
            
            return success
            
        except Exception as e:
            print(f"缓存标签热门内容失败: {e}")
            return False
    
    async def get_hot_content_by_tag(
        self,
        tag_id: int
    ) -> Optional[List[Dict[str, Any]]]:
        """获取标签热门内容缓存"""
        try:
            cache_key = self._generate_cache_key(
                "hot_content",
                tag_id=tag_id
            )
            
            cached_data = self.redis_utils.get(cache_key)
            if not cached_data:
                return None
            
            cache_info = json.loads(cached_data)
            hot_contents = cache_info.get("hot_contents", [])
            
            print(f"从缓存获取标签 {tag_id} 热门内容，共 {len(hot_contents)} 条")
            return hot_contents
            
        except Exception as e:
            print(f"获取标签热门内容缓存失败: {e}")
            return None
    
    async def cache_user_behavior(
        self,
        user_id: int,
        content_id: int,
        behavior_type: str,  # view, like, comment, share
        expire: int = 86400  # 24小时
    ) -> bool:
        """缓存用户行为数据"""
        try:
            cache_key = f"{self.cache_prefix}:behavior:{user_id}"
            
            # 获取现有行为数据
            existing_data = self.redis_utils.get(cache_key)
            if existing_data:
                behavior_data = json.loads(existing_data)
            else:
                behavior_data = {
                    "user_id": user_id,
                    "behaviors": {},
                    "last_updated": datetime.utcnow().isoformat()
                }
            
            # 更新行为数据
            if content_id not in behavior_data["behaviors"]:
                behavior_data["behaviors"][content_id] = {}
            
            behavior_data["behaviors"][content_id][behavior_type] = {
                "timestamp": datetime.utcnow().isoformat(),
                "count": behavior_data["behaviors"][content_id].get(behavior_type, {}).get("count", 0) + 1
            }
            
            behavior_data["last_updated"] = datetime.utcnow().isoformat()
            
            success = self.redis_utils.set(
                cache_key,
                json.dumps(behavior_data, ensure_ascii=False),
                expire
            )
            
            if success:
                print(f"用户 {user_id} 对内容 {content_id} 的 {behavior_type} 行为缓存成功")
            
            return success
            
        except Exception as e:
            print(f"缓存用户行为失败: {e}")
            return False
    
    async def get_user_behavior(
        self,
        user_id: int
    ) -> Optional[Dict[str, Any]]:
        """获取用户行为数据"""
        try:
            cache_key = f"{self.cache_prefix}:behavior:{user_id}"
            
            cached_data = self.redis_utils.get(cache_key)
            if not cached_data:
                return None
            
            behavior_data = json.loads(cached_data)
            print(f"从缓存获取用户 {user_id} 行为数据")
            return behavior_data
            
        except Exception as e:
            print(f"获取用户行为缓存失败: {e}")
            return None
    
    async def cache_tag_weights(
        self,
        user_id: int,
        tag_weights: Dict[int, float],
        expire: int = 3600  # 1小时
    ) -> bool:
        """缓存用户标签权重"""
        try:
            cache_key = f"{self.cache_prefix}:tag_weights:{user_id}"
            
            cache_data = {
                "user_id": user_id,
                "tag_weights": tag_weights,
                "cached_at": datetime.utcnow().isoformat()
            }
            
            success = self.redis_utils.set(
                cache_key,
                json.dumps(cache_data, ensure_ascii=False),
                expire
            )
            
            if success:
                print(f"用户 {user_id} 标签权重缓存成功")
            
            return success
            
        except Exception as e:
            print(f"缓存用户标签权重失败: {e}")
            return False
    
    async def get_tag_weights(
        self,
        user_id: int
    ) -> Optional[Dict[int, float]]:
        """获取用户标签权重"""
        try:
            cache_key = f"{self.cache_prefix}:tag_weights:{user_id}"
            
            cached_data = self.redis_utils.get(cache_key)
            if not cached_data:
                return None
            
            cache_info = json.loads(cached_data)
            tag_weights = cache_info.get("tag_weights", {})
            
            print(f"从缓存获取用户 {user_id} 标签权重")
            return tag_weights
            
        except Exception as e:
            print(f"获取用户标签权重缓存失败: {e}")
            return None
    
    async def cache_search_after(
        self,
        user_id: int,
        page: int,
        search_after: List,
        expire: int = 1800  # 30分钟
    ) -> bool:
        """缓存search_after分页信息"""
        try:
            cache_key = self._generate_cache_key(
                "search_after",
                user_id=user_id,
                page=page
            )
            
            cache_data = {
                "user_id": user_id,
                "page": page,
                "search_after": search_after,
                "cached_at": datetime.utcnow().isoformat()
            }
            
            success = self.redis_utils.set(
                cache_key,
                json.dumps(cache_data, ensure_ascii=False),
                expire
            )
            
            if success:
                print(f"用户 {user_id} 第 {page} 页search_after缓存成功")
            
            return success
            
        except Exception as e:
            print(f"缓存search_after失败: {e}")
            return False
    
    async def get_search_after(
        self,
        user_id: int,
        page: int
    ) -> Optional[List]:
        """获取search_after分页信息"""
        try:
            cache_key = self._generate_cache_key(
                "search_after",
                user_id=user_id,
                page=page
            )
            
            cached_data = self.redis_utils.get(cache_key)
            if not cached_data:
                return None
            
            cache_info = json.loads(cached_data)
            search_after = cache_info.get("search_after")
            
            print(f"从缓存获取用户 {user_id} 第 {page} 页search_after")
            return search_after
            
        except Exception as e:
            print(f"获取search_after缓存失败: {e}")
            return None
    
    async def clear_user_cache(self, user_id: int) -> bool:
        """清除用户相关缓存"""
        try:
            # 清除用户推荐缓存
            pattern = f"{self.cache_prefix}:user_rec:*user_id={user_id}*"
            # 这里需要实现模式匹配删除，简化处理
            
            # 清除用户行为缓存
            behavior_key = f"{self.cache_prefix}:behavior:{user_id}"
            self.redis_utils.delete(behavior_key)
            
            # 清除标签权重缓存
            weights_key = f"{self.cache_prefix}:tag_weights:{user_id}"
            self.redis_utils.delete(weights_key)
            
            print(f"用户 {user_id} 相关缓存清除成功")
            return True
            
        except Exception as e:
            print(f"清除用户缓存失败: {e}")
            return False
    
    async def get_cache_stats(self) -> Dict[str, Any]:
        """获取缓存统计信息"""
        try:
            # 这里可以添加更详细的缓存统计逻辑
            stats = {
                "cache_prefix": self.cache_prefix,
                "default_expire": self.default_expire,
                "hot_content_expire": self.hot_content_expire,
                "timestamp": datetime.utcnow().isoformat()
            }
            
            return stats
            
        except Exception as e:
            print(f"获取缓存统计失败: {e}")
            return {}

# 缓存策略配置
class CacheStrategy:
    """缓存策略配置"""
    
    # 推荐结果缓存策略
    RECOMMENDATION_CACHE = {
        "expire": 600,  # 10分钟
        "max_pages": 3,  # 最多缓存3页
        "enabled": True
    }
    
    # 热门内容缓存策略
    HOT_CONTENT_CACHE = {
        "expire": 3600,  # 1小时
        "max_count": 50,  # 每个标签最多缓存50条
        "enabled": True
    }
    
    # 用户行为缓存策略
    USER_BEHAVIOR_CACHE = {
        "expire": 86400,  # 24小时
        "max_behaviors": 1000,  # 最多缓存1000个行为
        "enabled": True
    }
    
    # 标签权重缓存策略
    TAG_WEIGHTS_CACHE = {
        "expire": 3600,  # 1小时
        "enabled": True
    }

if __name__ == "__main__":
    # 测试缓存功能
    async def test_cache():
        cache_manager = RecommendationCache()
        
        # 测试推荐结果缓存
        test_recommendations = [
            {"content_id": 1, "title": "测试内容1", "score": 0.9},
            {"content_id": 2, "title": "测试内容2", "score": 0.8}
        ]
        
        await cache_manager.cache_user_recommendations(
            user_id=1,
            page=1,
            recommendations=test_recommendations
        )
        
        cached_recs = await cache_manager.get_user_recommendations(
            user_id=1,
            page=1
        )
        
        print(f"缓存测试结果: {len(cached_recs) if cached_recs else 0} 条推荐")
        
        # 测试标签权重缓存
        tag_weights = {1: 2.0, 3: 1.5, 5: 1.0}
        await cache_manager.cache_tag_weights(
            user_id=1,
            tag_weights=tag_weights
        )
        
        cached_weights = await cache_manager.get_tag_weights(user_id=1)
        print(f"标签权重缓存测试: {cached_weights}")
    
    asyncio.run(test_cache())
